/*
============================================================================
 Name        : dd_log.c
 Author      : Jian
 Version     :
 Copyright   : GPL
 Description : dd_log.c - source file
============================================================================
*/

/* INCLUDE FILES */
#include "dd_log.h"
#include "sd_platform.h"

const static char* _logPriorityStr[] = {
    "TRACE", "WARN", "ERROR", "KEYPATH", "NO_LOG"
} ;

static sd_file*           _logFile= 0;
static DD_UINT            _logFileSize = 0;
static sd_rlock* _logLock = NULL;
static int                _logRecursionProtect = 0;
DD_UINT                   ddLogPriority = DD_DEFAULT_LOG_PRIORITY;


#define DD_MAX_LOG_BUF    256
#define DD_MAX_LOG_SIZE   (10 * 1024 * 1024)

int dd_log_init()
{
    _logRecursionProtect = 0 ;

    dd_log_set_prioriry(ddLogPriority) ;

    return 0 ;
}

int dd_log_close()
{
    if (_logLock) 
        sd_wait_rlock(_logLock) ;

    if (_logFile) {
        sd_file_close(_logFile);
        _logFile = 0 ;
    }

    if (_logLock)
        sd_post_rlock(_logLock) ;

    return 0;
}

static int _open_log_file() 
{
    int  i = 1 ;
    char name[DD_MAX_FILE_NAME_LEN + 1]= {0};
    char logPath[DD_MAX_FILE_NAME_LEN + 1]= {0};

    _logFileSize = 0 ;

    sd_get_log_path(logPath);

    if(logPath[0] == 0 || logPath[strlen(logPath) - 1] != DD_FILE_SPLASH) {
        __DD_ASSERT_DEFENSE(0, sd_sys_log(DD_LOG_PRIORITY_ERROR, "error get log path: %s form sd_get_log_path() function", logPath)) ;
        goto _error ;
    }

    if (!sd_is_folder_exist((const DD_UTF8*)logPath) && sd_create_folder((const DD_UTF8*)logPath) < 0) {
        __DD_ASSERT_DEFENSE(0, sd_sys_log(DD_LOG_PRIORITY_ERROR, "error create log folder: %s", logPath)) ;
        goto _error ;
    }

    for (; i < 100; i++) {

        int found = 0 ;
        _logFileSize = 0 ;

        name[0] = 0 ;
        sprintf(name, "%splayer%d.log", logPath, i);

        if (!sd_is_file_exist((const DD_UTF8*)name)) {
            found = 1 ;
        } else {
            sd_get_file_size((const DD_UTF8*)name, &_logFileSize);
            if (_logFileSize < (DD_MAX_LOG_SIZE - (100 * 1024)))
                found = 2 ;
        }

        if (found) {
            _logFile = sd_file_open((const DD_UTF8*)name, (found == 1) ? DD_FILE_REPLACE : DD_FILE_READ_WRITE);
            if (_logFile) {
                sd_file_seek(_logFile, 0, DD_SEEK_END);
                break ;
            }
        }
    }

    if (!_logFile) {
        sd_sys_log(DD_LOG_PRIORITY_TRACE, "failed to open log file:%s", name);
        goto _error;
    }

    dd_log_trace("init log file succeed whth logIndex: %d", i) ;

    return 0 ;

_error:

    if (_logFileSize < 0) _logFileSize = 0;

    ddLogPriority = DD_LOG_PRIORITY_NO_LOG ;

    return -1;
}

static void _log(int priority, const char* format, va_list vaList)
{
    char    buffer[DD_MAX_LOG_BUF + 1] = {0};
    char    logPath[DD_MAX_FILE_NAME_LEN]= {0};
    char    timeStr[DD_MAX_TIME_STR_LEN + 1] = {0};
    char    threadInfo[DD_MAX_THREAD_INFO_LEN + 1] = {0};
    int     bufLen = 0, bytesWrite = 0;
    int     exsitSize = 0 ;

    if (ddLogPriority >= DD_LOG_PRIORITY_NO_LOG || priority < ddLogPriority) 
        return ;

    sd_get_time_string(timeStr) ;
    sd_get_thread_info(threadInfo) ;

    sprintf(buffer, "%s  %s  %s ", (char *)timeStr, threadInfo, _logPriorityStr[priority]);

    exsitSize = strlen(buffer);

    vsnprintf(buffer + exsitSize, DD_MAX_LOG_BUF - 2 - exsitSize, format, vaList);

    bufLen = strlen(buffer);
    buffer[bufLen] = '\n';
    buffer[bufLen+1] = 0;
    bufLen += 1;

    sd_sys_log(priority, buffer);

    if(!_logLock) {
        _logRecursionProtect = 0 ;
        return;
    }

    sd_wait_rlock(_logLock);

    if (_logRecursionProtect > 0) {
        sd_post_rlock(_logLock);
        return ;
    }

    _logRecursionProtect++ ;

    if (_logFile) {
        sd_file_write(_logFile, buffer, bufLen) ;
        sd_file_fulsh(_logFile);
    }

    _logFileSize += bufLen;
    if (_logFileSize >= DD_MAX_LOG_SIZE || _logFile == NULL) {
        if (_logFile)
            sd_file_close(_logFile);

        _logFile = NULL ;
        _open_log_file() ;
    }

    _logRecursionProtect = 0 ;

    sd_post_rlock(_logLock);
}

void dd_log_traced(const char* format, ...) 
{
    va_list vaList;
    va_start (vaList, format);
    _log(DD_LOG_PRIORITY_TRACE, format, vaList) ;
    va_end (vaList);
}

void dd_log_warnd(const char* format, ...) 
{
    va_list vaList;
    va_start (vaList, format);
    _log(DD_LOG_PRIORITY_WARN, format, vaList) ;
    va_end (vaList);
}

void dd_log_errord(const char* format, ...) 
{
    va_list vaList;
    va_start (vaList, format);
    _log(DD_LOG_PRIORITY_ERROR, format, vaList) ;
    va_end (vaList);
}

void dd_log_keypathd(const char* format, ...) 
{
    va_list vaList;
    va_start (vaList, format);
    _log(DD_LOG_PRIORITY_KEYPATH, format, vaList) ;
    va_end (vaList);
}

int dd_log_set_prioriry(DD_UINT priority) 
{
    __DD_ASSERT_DEFENSE(priority <= DD_LOG_PRIORITY_NO_LOG, return -1) ;

    ddLogPriority = priority ;

    #ifdef __DD_LOG

    if (ddLogPriority >= DD_LOG_PRIORITY_NO_LOG) {
        sd_sys_log(DD_LOG_PRIORITY_TRACE, "log priority:%d, just don't do anything for log", ddLogPriority) ;
        dd_log_close() ;
        return 0 ;
    }

    _logRecursionProtect = 0 ;

    if (!_logLock)
        _logLock = sd_create_rlock();

    _open_log_file() ;
    
    return 0 ;

    #endif
}



/* End of File */
